package main

import (
	"context"
	"crypto/ecdsa"
	"fmt"
	"log"
	"math/big"
	"strings"
	"time"

	"github.com/ethereum/go-ethereum/accounts/abi"
	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/ethclient"
)

// SimpleStorage 合约 ABI
const SimpleStorageABI = `[
	{
		"inputs": [],
		"stateMutability": "nonpayable",
		"type": "constructor"
	},
	{
		"anonymous": false,
		"inputs": [
			{
				"indexed": true,
				"internalType": "address",
				"name": "user",
				"type": "address"
			},
			{
				"indexed": true,
				"internalType": "uint256",
				"name": "value",
				"type": "uint256"
			},
			{
				"indexed": false,
				"internalType": "uint256",
				"name": "timestamp",
				"type": "uint256"
			}
		],
		"name": "DataStored",
		"type": "event"
	},
	{
		"anonymous": false,
		"inputs": [
			{
				"indexed": true,
				"internalType": "address",
				"name": "previousOwner",
				"type": "address"
			},
			{
				"indexed": true,
				"internalType": "address",
				"name": "newOwner",
				"type": "address"
			}
		],
		"name": "OwnershipTransferred",
		"type": "event"
	},
	{
		"inputs": [
			{
				"internalType": "uint256",
				"name": "_value",
				"type": "uint256"
			}
		],
		"name": "set",
		"outputs": [],
		"stateMutability": "nonpayable",
		"type": "function"
	},
	{
		"inputs": [],
		"name": "get",
		"outputs": [
			{
				"internalType": "uint256",
				"name": "",
				"type": "uint256"
			}
		],
		"stateMutability": "view",
		"type": "function"
	},
	{
		"inputs": [
			{
				"internalType": "address",
				"name": "_user",
				"type": "address"
			}
		],
		"name": "getUserValue",
		"outputs": [
			{
				"internalType": "uint256",
				"name": "",
				"type": "uint256"
			}
		],
		"stateMutability": "view",
		"type": "function"
	},
	{
		"inputs": [
			{
				"internalType": "uint256",
				"name": "_amount",
				"type": "uint256"
			}
		],
		"name": "increment",
		"outputs": [],
		"stateMutability": "nonpayable",
		"type": "function"
	},
	{
		"inputs": [],
		"name": "reset",
		"outputs": [],
		"stateMutability": "nonpayable",
		"type": "function"
	},
	{
		"inputs": [
			{
				"internalType": "address",
				"name": "_newOwner",
				"type": "address"
			}
		],
		"name": "transferOwnership",
		"outputs": [],
		"stateMutability": "nonpayable",
		"type": "function"
	},
	{
		"inputs": [],
		"name": "getContractInfo",
		"outputs": [
			{
				"internalType": "address",
				"name": "_owner",
				"type": "address"
			},
			{
				"internalType": "uint256",
				"name": "_storedData",
				"type": "uint256"
			},
			{
				"internalType": "uint256",
				"name": "_contractBalance",
				"type": "uint256"
			}
		],
		"stateMutability": "view",
		"type": "function"
	},
	{
		"inputs": [],
		"name": "withdraw",
		"outputs": [],
		"stateMutability": "nonpayable",
		"type": "function"
	},
	{
		"inputs": [],
		"name": "owner",
		"outputs": [
			{
				"internalType": "address",
				"name": "",
				"type": "address"
			}
		],
		"stateMutability": "view",
		"type": "function"
	},
	{
		"inputs": [
			{
				"internalType": "address",
				"name": "",
				"type": "address"
			}
		],
		"name": "userValues",
		"outputs": [
			{
				"internalType": "uint256",
				"name": "",
				"type": "uint256"
			}
		],
		"stateMutability": "view",
		"type": "function"
	},
	{
		"stateMutability": "payable",
		"type": "receive"
	}
]`

// SimpleStorage 合约字节码 (编译后的)
// 注意：这是一个简化的字节码，实际使用时需要用 solc 编译器生成
const SimpleStorageBytecode = "0x608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000808190555060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36108f8806100d36000396000f3fe6080604052600436106100a75760003560e01c80638da5cb5b116100645780638da5cb5b146101a5578063a2fb1175146101d0578063d0ebdbe7146101fb578063d826f88f14610224578063f2fde38b1461023b578063f3fef3a314610264576100ae565b806306661abd146100b35780633ccfd60b146100de5780636057361d146100f557806367e404ce1461011e5780637bd703e81461014957806383197ef014610186576100ae565b366100ae57005b600080fd5b3480156100bf57600080fd5b506100c861028b565b6040516100d59190610742565b60405180910390f35b3480156100ea57600080fd5b506100f3610291565b005b34801561010157600080fd5b5061011c600480360381019061011791906106f5565b610387565b005b34801561012a57600080fd5b50610133610485565b60405161014091906106d4565b60405180910390f35b34801561015557600080fd5b50610170600480360381019061016b91906106a8565b6104ab565b60405161017d9190610742565b60405180910390f35b34801561019257600080fd5b5061019b6104c3565b005b3480156101b157600080fd5b506101ba610556565b6040516101c791906106d4565b60405180910390f35b3480156101dc57600080fd5b506101e561057c565b6040516101f293929190610719565b60405180910390f35b34801561020757600080fd5b50610222600480360381019061021d91906106a8565b6105c6565b005b34801561023057600080fd5b50610239610736565b005b34801561024757600080fd5b50610262600480360381019061025d91906106a8565b6107c4565b005b34801561027057600080fd5b5061028b600480360381019061028691906106f5565b6108b9565b005b60015481565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610320576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610317906107a4565b60405180910390fd5b60004790506000811161036857604051806020016040528060008152506040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161035f91906107a4565b60405180910390fd5b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f193505050501580156103ce573d6000803e3d6000fd5b5050565b600081116103f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103ec906107a4565b60405180910390fd5b806001819055508060026000336040516020016104129190610719565b6040516020818303038152906040528051906020012073ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550336040516020016104779190610719565b60405180910390a150565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60026020528060005260406000206000915090505481565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610552576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610549906107a4565b60405180910390fd5b6000600181905550336040516020016105029190610719565b60405180910390a1565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600154479250925092509091925090565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610655576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161064c906107a4565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156106c5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106bc906107a4565b60405180910390fd5b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415610754576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074b906107a4565b60405180910390fd5b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508060008054906101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610847576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161083e906107a4565b60405180910390fd5b60008111610884576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161087b906107a4565b60405180910390fd5b806001600082825461089691906107c4565b925050819055508060026000336040516020016108b39190610719565b6040516020818303038152906040528051906020012073ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546108f191906107c4565b92505081905550336040516020016109099190610719565b60405180910390a150565b600081359050610923816108ab565b92915050565b600081359050610938816108c2565b92915050565b60006020828403121561095057600080fd5b600061095e84828501610914565b91505092915050565b60006020828403121561097957600080fd5b600061098784828501610929565b91505092915050565b61099981610832565b82525050565b6109a881610844565b82525050565b60006109b98261081c565b6109c38185610827565b93506109d3818560208601610871565b6109dc816108a4565b840191505092915050565b60006109f4602683610827565b91507f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008301527f64647265737300000000000000000000000000000000000000000000000000006020830152604082019050919050565b6000610a5a602083610827565b91507f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726000830152602082019050919050565b6000610a9a602683610827565b91507f56616c7565206d75737420626520677265617465722074686120000000000000600083015250602082019050919050565b610ad68161085a565b82525050565b6000602082019050610af16000830184610990565b92915050565b600060608201905081810360008301526000610b1360208401610990565b9050610b226020840184610acd565b610b2f6040840184610acd565b8091505092915050565b60006020820190508181036000830152610b5381846109ae565b905092915050565b60006020820190508181036000830152610b74816109e7565b9050919050565b60006020820190508181036000830152610b9481610a4d565b9050919050565b60006020820190508181036000830152610bb481610a8d565b9050919050565b6000602082019050610bd06000830184610acd565b92915050565b6000610be18261085a565b9150610bec8361085a565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115610c2157610c20610877565b5b828201905092915050565b6000610c378261083a565b9050919050565b60008115159050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60005b83811015610c9b578082015181840152602081019050610c80565b83811115610caa576000848401525b50505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000601f19601f8301169050919050565b610cf481610c2c565b8114610cff57600080fd5b50565b610d0b8161085a565b8114610d1657600080fd5b5056fea26469706673582212208f5d5e5d5e5d5e5d5e5d5e5d5e5d5e5d5e5d5e5d5e5d5e5d5e5d5e5d5e5d5e64736f6c63430008070033"

// ContractDeployer 合约部署器
type ContractDeployer struct {
	client     *ethclient.Client
	privateKey *ecdsa.PrivateKey
	address    common.Address
	chainID    *big.Int
}

// NewContractDeployer 创建合约部署器
func NewContractDeployer(rpcURL, privateKeyHex string) (*ContractDeployer, error) {
	// 连接到以太坊节点
	client, err := ethclient.Dial(rpcURL)
	if err != nil {
		return nil, fmt.Errorf("连接到以太坊节点失败: %v", err)
	}

	// 解析私钥
	privateKey, err := crypto.HexToECDSA(privateKeyHex)
	if err != nil {
		return nil, fmt.Errorf("解析私钥失败: %v", err)
	}

	// 获取地址
	publicKey := privateKey.Public()
	publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
	if !ok {
		return nil, fmt.Errorf("获取公钥失败")
	}
	address := crypto.PubkeyToAddress(*publicKeyECDSA)

	// 获取链 ID
	chainID, err := client.NetworkID(context.Background())
	if err != nil {
		return nil, fmt.Errorf("获取链 ID 失败: %v", err)
	}

	return &ContractDeployer{
		client:     client,
		privateKey: privateKey,
		address:    address,
		chainID:    chainID,
	}, nil
}

// DeployContract 部署合约
func (cd *ContractDeployer) DeployContract() (common.Address, *types.Transaction, error) {
	// 获取账户 nonce
	nonce, err := cd.client.PendingNonceAt(context.Background(), cd.address)
	if err != nil {
		return common.Address{}, nil, fmt.Errorf("获取 nonce 失败: %v", err)
	}

	// 获取 gas 价格
	gasPrice, err := cd.client.SuggestGasPrice(context.Background())
	if err != nil {
		return common.Address{}, nil, fmt.Errorf("获取 gas 价格失败: %v", err)
	}

	// 创建交易选项
	auth, err := bind.NewKeyedTransactorWithChainID(cd.privateKey, cd.chainID)
	if err != nil {
		return common.Address{}, nil, fmt.Errorf("创建交易选项失败: %v", err)
	}

	auth.Nonce = big.NewInt(int64(nonce))
	auth.Value = big.NewInt(0)      // 不发送以太币
	auth.GasLimit = uint64(3000000) // 设置 gas 限制
	auth.GasPrice = gasPrice

	// 解析 ABI
	parsedABI, err := abi.JSON(strings.NewReader(SimpleStorageABI))
	if err != nil {
		return common.Address{}, nil, fmt.Errorf("解析 ABI 失败: %v", err)
	}

	// 部署合约
	address, tx, _, err := bind.DeployContract(
		auth,
		parsedABI,
		common.FromHex(SimpleStorageBytecode),
		cd.client,
	)

	if err != nil {
		return common.Address{}, nil, fmt.Errorf("部署合约失败: %v", err)
	}

	fmt.Printf("📄 合约部署交易: %s\n", tx.Hash().Hex())
	fmt.Printf("📍 预计合约地址: %s\n", address.Hex())

	return address, tx, nil
}

// WaitForDeployment 等待合约部署完成
func (cd *ContractDeployer) WaitForDeployment(txHash common.Hash) (*types.Receipt, error) {
	fmt.Printf("⏳ 等待合约部署确认...\n")

	for i := 0; i < 60; i++ {
		receipt, err := cd.client.TransactionReceipt(context.Background(), txHash)
		if err == nil {
			if receipt.Status == 1 {
				fmt.Printf("✅ 合约部署成功！\n")
				fmt.Printf("   合约地址: %s\n", receipt.ContractAddress.Hex())
				fmt.Printf("   区块号: %d\n", receipt.BlockNumber.Uint64())
				fmt.Printf("   Gas 使用量: %d\n", receipt.GasUsed)
				return receipt, nil
			} else {
				return nil, fmt.Errorf("合约部署失败：交易执行失败")
			}
		}

		time.Sleep(2 * time.Second)
		if i%5 == 4 {
			fmt.Printf("   仍在等待确认... (%d/60)\n", i+1)
		}
	}

	return nil, fmt.Errorf("等待合约部署超时")
}

// InteractWithContract 与合约交互
func (cd *ContractDeployer) InteractWithContract(contractAddress common.Address) error {
	// 解析 ABI
	parsedABI, err := abi.JSON(strings.NewReader(SimpleStorageABI))
	if err != nil {
		return fmt.Errorf("解析 ABI 失败: %v", err)
	}

	// 创建合约实例
	contract := bind.NewBoundContract(contractAddress, parsedABI, cd.client, cd.client, cd.client)

	// 创建交易选项
	auth, err := bind.NewKeyedTransactorWithChainID(cd.privateKey, cd.chainID)
	if err != nil {
		return fmt.Errorf("创建交易选项失败: %v", err)
	}

	// 获取当前 nonce
	nonce, err := cd.client.PendingNonceAt(context.Background(), cd.address)
	if err != nil {
		return fmt.Errorf("获取 nonce 失败: %v", err)
	}

	auth.Nonce = big.NewInt(int64(nonce))
	auth.Value = big.NewInt(0)
	auth.GasLimit = uint64(300000)

	// 获取 gas 价格
	gasPrice, err := cd.client.SuggestGasPrice(context.Background())
	if err != nil {
		return fmt.Errorf("获取 gas 价格失败: %v", err)
	}
	auth.GasPrice = gasPrice

	fmt.Println("\n🔄 开始与合约交互...")

	// 1. 调用 set 方法设置值
	fmt.Println("1️⃣ 设置存储值为 42")
	tx, err := contract.Transact(auth, "set", big.NewInt(42))
	if err != nil {
		return fmt.Errorf("调用 set 方法失败: %v", err)
	}

	// 等待交易确认
	fmt.Printf("   交易哈希: %s\n", tx.Hash().Hex())
	receipt, err := cd.waitForTransaction(tx.Hash())
	if err != nil {
		return fmt.Errorf("等待交易确认失败: %v", err)
	}
	fmt.Printf("   ✅ 交易确认，Gas 使用量: %d\n", receipt.GasUsed)

	// 2. 调用 get 方法获取值
	fmt.Println("2️⃣ 获取存储的值")
	var result []interface{}
	err = contract.Call(&bind.CallOpts{}, &result, "get")
	if err != nil {
		return fmt.Errorf("调用 get 方法失败: %v", err)
	}
	fmt.Printf("   存储的值: %s\n", result[0].(*big.Int).String())

	// 3. 获取合约所有者
	fmt.Println("3️⃣ 获取合约所有者")
	var owner []interface{}
	err = contract.Call(&bind.CallOpts{}, &owner, "owner")
	if err != nil {
		return fmt.Errorf("调用 owner 方法失败: %v", err)
	}
	fmt.Printf("   合约所有者: %s\n", owner[0].(common.Address).Hex())

	// 4. 获取用户存储的值
	fmt.Println("4️⃣ 获取用户存储的值")
	var userValue []interface{}
	err = contract.Call(&bind.CallOpts{}, &userValue, "getUserValue", cd.address)
	if err != nil {
		return fmt.Errorf("调用 getUserValue 方法失败: %v", err)
	}
	fmt.Printf("   用户 %s 存储的值: %s\n", cd.address.Hex(), userValue[0].(*big.Int).String())

	// 5. 增加存储的值
	fmt.Println("5️⃣ 增加存储值 10")
	auth.Nonce = big.NewInt(int64(nonce + 1))
	tx, err = contract.Transact(auth, "increment", big.NewInt(10))
	if err != nil {
		return fmt.Errorf("调用 increment 方法失败: %v", err)
	}

	fmt.Printf("   交易哈希: %s\n", tx.Hash().Hex())
	receipt, err = cd.waitForTransaction(tx.Hash())
	if err != nil {
		return fmt.Errorf("等待交易确认失败: %v", err)
	}
	fmt.Printf("   ✅ 交易确认，Gas 使用量: %d\n", receipt.GasUsed)

	// 6. 再次获取值验证
	fmt.Println("6️⃣ 验证增加后的值")
	err = contract.Call(&bind.CallOpts{}, &result, "get")
	if err != nil {
		return fmt.Errorf("调用 get 方法失败: %v", err)
	}
	fmt.Printf("   更新后的值: %s\n", result[0].(*big.Int).String())

	// 7. 获取合约信息
	fmt.Println("7️⃣ 获取合约完整信息")
	var contractInfo []interface{}
	err = contract.Call(&bind.CallOpts{}, &contractInfo, "getContractInfo")
	if err != nil {
		return fmt.Errorf("调用 getContractInfo 方法失败: %v", err)
	}
	fmt.Printf("   合约所有者: %s\n", contractInfo[0].(common.Address).Hex())
	fmt.Printf("   存储数据: %s\n", contractInfo[1].(*big.Int).String())
	fmt.Printf("   合约余额: %s Wei\n", contractInfo[2].(*big.Int).String())

	return nil
}

// waitForTransaction 等待交易确认
func (cd *ContractDeployer) waitForTransaction(txHash common.Hash) (*types.Receipt, error) {
	for i := 0; i < 30; i++ {
		receipt, err := cd.client.TransactionReceipt(context.Background(), txHash)
		if err == nil {
			if receipt.Status == 1 {
				return receipt, nil
			} else {
				return nil, fmt.Errorf("交易执行失败")
			}
		}
		time.Sleep(2 * time.Second)
	}
	return nil, fmt.Errorf("等待交易确认超时")
}

// DemoContractDeployment 演示合约部署和交互
func DemoContractDeployment() {
	fmt.Println("🚀 开始智能合约部署演示...")

	// 使用开发模式的默认私钥
	// 注意：这是开发环境的测试私钥，不要在生产环境使用
	privateKeyHex := "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"

	// 创建合约部署器
	deployer, err := NewContractDeployer("http://localhost:8545", privateKeyHex)
	if err != nil {
		log.Fatalf("创建合约部署器失败: %v", err)
	}

	fmt.Printf("📝 部署账户: %s\n", deployer.address.Hex())

	// 检查账户余额
	balance, err := deployer.client.BalanceAt(context.Background(), deployer.address, nil)
	if err != nil {
		log.Fatalf("获取账户余额失败: %v", err)
	}
	fmt.Printf("💰 账户余额: %s ETH\n", weiToEther(balance).String())

	// 部署合约
	fmt.Println("\n📄 部署 SimpleStorage 合约...")
	contractAddress, deployTx, err := deployer.DeployContract()
	if err != nil {
		log.Fatalf("部署合约失败: %v", err)
	}

	// 等待部署完成
	receipt, err := deployer.WaitForDeployment(deployTx.Hash())
	if err != nil {
		log.Fatalf("等待合约部署失败: %v", err)
	}

	// 与合约交互
	fmt.Println("\n🤝 与合约交互...")
	err = deployer.InteractWithContract(receipt.ContractAddress)
	if err != nil {
		log.Fatalf("与合约交互失败: %v", err)
	}

	fmt.Println("\n🎉 智能合约部署和交互演示完成！")
	fmt.Printf("📍 合约地址: %s\n", receipt.ContractAddress.Hex())
}

// weiToEther 将 wei 转换为 ether
func weiToEther(wei *big.Int) *big.Float {
	ether := new(big.Float)
	ether.SetString(wei.String())
	return ether.Quo(ether, big.NewFloat(1e18))
}

func main() {
	DemoContractDeployment()
}
